#ifndef __ADDRESS_MAPPING_CONFIG_H__
#define __ADDRESS_MAPPING_CONFIG_H__

#include "sst/core/unitAlgebra.h"
#include "sst/elements/memHierarchy/util.h"

#define RANK_BITS       4
#define BANKGROUP_BITS  1
#define BANK_BITS       2
#define ROW_BITS        16
#define COLUMN_BITS     10
#define OFFSET_BITS     3

typedef enum class MyRowPolicy
{
    CLOSED = 0,
    OPEN,
    INVALID
}MyRowPolicy;

typedef enum class MyQueuePolicy
{
    PER_BANK = 0,
    PER_RANK,
    INVALID
} MyQueuePolicy;


typedef struct TimeParameters
{
    uint64_t tRCD;      // Row access latency (RCD)
    uint64_t tAL;         // Address latch latency
    uint64_t tCL;         // Column latency
    uint64_t tCWL;       // Column write latency, if applicable
    uint64_t tRP;        // Row precharge time
    uint64_t tRAS;       // Row active time, if applicable
    uint64_t tBurstCycle; // Burst cycle time
    uint64_t tRRD;       // Minimum time interval between two ACTIVATE commands to different banks within the same rank
    uint64_t tRRD_L;     // Minimum time interval between two ACTIVATE commands
    uint64_t tRRD_S;     // Minimum time interval between two ACTIVATE commands to banks in different bank groups in DDR4
    uint64_t tFAW;      // Fast access window, if applicable

} TimeParameters;

typedef struct AddressMappingParameters
{
    size_t memSize;    // Memory size
    uint64_t bus_width;      // Width of the bus in bits
    uint64_t device_width;   // Device size in bytes
    uint64_t bankGroups;    // Number of bank groups
    uint64_t banksPerGroup; // Number of banks per group
    uint64_t rows;          // Number of rows
    uint64_t columns;       // Number of columns
    uint64_t BL;           // Burst length in bytes (B), must be a power of 2

} AddressMappingParameters;

typedef struct PolicyParameters
{
    
    MyRowPolicy rowPolicy;      // Row policy (CLOSED, OPEN)
    MyQueuePolicy queuePolicy;  // Queue policy (PER_BANK, PER_RANK)
    uint64_t transQueueSize;   // Transaction queue size
    uint64_t cmdQueueSize;     // Command queue size

} PolicyParameters;



class AddressMappingConfig
{
private:

    // Time parameters

    uint64_t tRCD;
    uint64_t tAL;        
    uint64_t tCL;  
    uint64_t tCWL; // Column write latency, if applicable
    uint64_t tRP; // Row precharge time     
    uint64_t tRAS; // Row active time, if applicable  
    uint64_t tBurstCycle; 
    uint64_t tRRD; // Minimum time interval between two ACTIVATE commands to different banks within the same rank
    uint64_t tRRD_L; // Minimum time interval between two ACTIVATE commands to
    uint64_t tRRD_S; // Minimum time interval between two ACTIVATE commands to banks in different bank groups in DDR4
    uint64_t tFAW; // Fast access window, if applicable



    // Policy parameters
    MyRowPolicy rowPolicy;
    MyQueuePolicy queuePolicy;
    uint64_t trans_queue_size;
    uint64_t cmd_queue_size; // Command queue size, if applicable

    // DRAM parameters
    size_t memSize;
    uint64_t bus_width;      // Width of the bus in bits
    uint64_t device_width;

    uint64_t ranks;
    uint64_t bankGroups;
    uint64_t banksPerGroup;
    uint64_t rows;
    uint64_t columns;
    uint64_t BL; // Burst length in bytes (B), must be a power of 2

    uint64_t rankOffset;
    uint64_t bankGroupOffset;
    uint64_t bankOffset;
    uint64_t rowOffset;
    uint64_t columnOffset;
    // uint64_t lineOffset; 

    uint64_t rankMask;
    uint64_t bankGroupMask;
    uint64_t bankMask;
    uint64_t rowMask;
    uint64_t columnMask;
    // uint64_t lineMask; 

    uint64_t shift_bits;

public:
    AddressMappingConfig();
    AddressMappingConfig(TimeParameters *TP, AddressMappingParameters *AMP, PolicyParameters *PP);
    uint64_t ALogBase2(uint64_t power_of_two);

    uint64_t getTRCD() const { return tRCD; }
    uint64_t getTAL() const { return tAL; }
    uint64_t getTCL() const { return tCL; }
    uint64_t getTCWL() const { return tCWL; } // Column write latency
    uint64_t getTRP() const { return tRP; }
    uint64_t getTRAS() const { return tRAS; } // Row active time
    uint64_t getTBurstCycle() const { return tBurstCycle; }
    uint64_t getTRRD() const { return tRRD; } 
    uint64_t getTRRD_L() const { return tRRD_L; } 
    uint64_t getTRRD_S() const { return tRRD_S; } 
    uint64_t getTFAW() const { return tFAW; } // Fast access window, if applicable
    
    MyRowPolicy getRowPolicy() const { return rowPolicy; }
    MyQueuePolicy getQueuePolicy() const { return queuePolicy; }
    uint64_t getTransQueueSize() const {return trans_queue_size; }
    uint64_t getCmdQueueSize() const { return cmd_queue_size; }
    
    uint64_t getMemSize() const { return memSize; }
    uint64_t getBusWidth() const { return bus_width; }
    uint64_t getDeviceWidth() const { return device_width; }
    uint64_t getRanks() const { return ranks; }
    uint64_t getBankGroups() const { return bankGroups; }
    uint64_t getBanksPerGroup() const { return banksPerGroup; }
    uint64_t getRows() const { return rows; }
    uint64_t getColumns() const { return columns; }
    uint64_t getBL() const { return BL; } // Burst length in bytes (B)
    uint64_t getRankOffset() const { return rankOffset; }
    uint64_t getBankGroupOffset() const { return bankGroupOffset; }
    uint64_t getBankOffset() const { return bankOffset; }
    uint64_t getRowOffset() const { return rowOffset; }
    uint64_t getColumnOffset() const { return columnOffset; }
    // uint64_t getLineOffset() const { return lineOffset; }
    uint64_t getRankMask() const { return rankMask; }
    uint64_t getBankGroupMask() const { return bankGroupMask; }
    uint64_t getBankMask() const { return bankMask; }
    uint64_t getRowMask() const { return rowMask; }
    uint64_t getColumnMask() const { return columnMask; }
    // uint64_t getLineMask() const { return lineMask; }
    uint64_t getShiftBits() const { return shift_bits; }


};

#endif